package web.pda.sgcc.com.websdk.util;

import android.app.Fragment;
import android.content.Context;
import android.text.TextUtils;
import android.util.Log;

import com.sgcc.pda.baselibrary.utils.JsonUtil;
import com.sgcc.pda.baselibrary.utils.LogUtil;
import com.sgcc.pda.baselibrary.utils.ToastUtils;
import com.sgcc.pda.newsm4.SM4Utils;
import com.sgcc.pda.sdk.utils.DataConversionUtil;
import com.sgcc.pda.sdk.utils.ZoomSPUtils;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.net.SocketTimeoutException;
import java.net.URLEncoder;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.MultipartBody;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
import web.pda.sgcc.com.websdk.http.BaseRequestParams;
import web.pda.sgcc.com.websdk.http.Mybody;
import web.pda.sgcc.com.websdk.http.OkHttpManager;
import web.pda.sgcc.com.websdk.http.UIHandler;

import static com.sgcc.pda.sdk.utils.ConstantSM4.SM4_IV;
import static com.sgcc.pda.sdk.utils.ConstantSM4.SM4_KEY;

/**
 * okhttp 工具类
 */
public class HttpClientUtil {
    private static final String SERVER_ERROR = "Server Error.";
    private static final String SESSION_OUT_OF_TIME = "会话超时，UID失效";
    private static String TAG = "HttpClientUtil";
    private static Request request;

    private static HashMap<String, Call> downCalls;//用来存放各个下载的请求
    private static OkHttpClient mClient;


    // 防止实例化
    private HttpClientUtil() {
    }

    private enum METHOD {
        PUT, POST, GET, DELETE
    }

    /**
     * HTTP请求
     */
    private static void httpRequest(
            final Context context,
            final Object callObject,
            METHOD method,
            final String url,
            final String header,
            final BaseRequestParams params,
            final OkHttpManager.Listener<String> listener,
            final OkHttpManager.ErrorListener errorListener) {

        Request.Builder requestBuilder = createRequestBuilder(context, callObject, method, url, header, params);


        OkHttpManager.getClient(context).newCall(requestBuilder.build()).enqueue(new Callback() {
            @Override
            public void onFailure(Call call, final IOException e) {
                e.printStackTrace();
                onHttpRequestFail(e, errorListener);
            }

            @Override
            public void onResponse(Call call, Response response) throws IOException {
                onHttpRequestResponse(response, listener, errorListener);
            }
        });
    }

    /**
     * HTTP同步请求
     */
    private static void httpRequestSync(
            final Context context,
            final Object callObject,
            METHOD method,
            final String url,
            final String header,
            final BaseRequestParams params,
            final OkHttpManager.Listener<String> listener,
            final OkHttpManager.ErrorListener errorListener) {

        Request.Builder requestBuilder = createRequestBuilder(context, callObject, method, url, header, params);

        try {
            Response response = OkHttpManager.getClient(context)
                    .newCall(requestBuilder.build())
                    .execute();

            onHttpRequestSyncResponse(response, listener, errorListener);
        } catch (IOException e) {
            e.printStackTrace();
            onHttpRequestSyncFail(e, errorListener);
        }
    }

    /**
     * 创建HTTP请求
     */
    private static Request.Builder createRequestBuilder(Context context, Object callObject, METHOD method, String url, String header, BaseRequestParams params) {
        Request.Builder requestBuilder = null;
        switch (method) {
            case POST: {
                MultipartBody.Builder body = params.createMultipartBody();
                body.setType(MultipartBody.FORM);
                if (!TextUtils.isEmpty(header)) {
                    try {
                        HashMap<String, String> hashMap = JsonUtil.parseJsonToBean(header, HashMap.class);
                        requestBuilder = new Request.Builder();
                        requestBuilder.url(url);
                        for (Map.Entry<String, String> entry : hashMap.entrySet()) {
                            LogUtil.e("hehe", "key:" + entry.getKey() + "//value:" + entry.getValue());
                            requestBuilder.addHeader(entry.getKey(), entry.getValue());
                        }
                        requestBuilder.post(body.build());
                        requestBuilder.tag(callObject);
                    } catch (Exception e) {
                        ToastUtils.showToast(context, "请求头参数不合法");
                    }

                } else {
                    requestBuilder = new Request.Builder()
                            .url(url)
                            .post(body.build())
                            .tag(callObject);
                }

                break;
            }
            case PUT: {
                MultipartBody.Builder body = params.createMultipartBody();
                body.setType(MultipartBody.FORM);
                requestBuilder = new Request.Builder()
                        .url(url)
                        .put(body.build())
                        .tag(callObject);
                break;
            }
            case DELETE: {
                MultipartBody.Builder body = params.createMultipartBody();
                body.setType(MultipartBody.FORM);
                requestBuilder = new Request.Builder()
                        .url(url)
                        .delete(body.build())
                        .tag(callObject);
                break;
            }
            case GET: {
                String getUrl;
                StringBuilder sb = new StringBuilder();
                sb.append(url + "?");

                try {
                    for (ConcurrentHashMap.Entry<String, String> entry : params.urlParams.entrySet()) {
                        sb.append(URLEncoder.encode(entry.getKey(), "UTF-8"));
                        sb.append('=');
                        sb.append(URLEncoder.encode(entry.getValue(), "UTF-8"));
                        sb.append('&');
                    }
                    getUrl = sb.substring(0, sb.length() - 1);
                } catch (UnsupportedEncodingException uee) {
                    uee.printStackTrace();
                    getUrl = sb.toString();
                }

                requestBuilder = new Request.Builder()
                        .url(getUrl)
                        .get()
                        .tag(callObject);
                break;
            }
            default: {
                requestBuilder = new Request.Builder()
                        .url(url)
                        .get()
                        .tag(callObject);
            }
            break;

        }

        return requestBuilder;
    }

    /**
     * HTTP请求失败处理
     */
    private static void onHttpRequestFail(final IOException e, final OkHttpManager.ErrorListener errorListener) {
        UIHandler.get().post(new Runnable() {
            @Override
            public void run() {
                if (errorListener != null) {
                    errorListener.onErrorResponse(new OkHttpManager.OkHttpError(e.getMessage()));
                }
            }
        });
    }

    /**
     * HTTP请求成功结果处理
     */
    private static void onHttpRequestResponse(Response response,
                                              final OkHttpManager.Listener<String> listener,
                                              OkHttpManager.ErrorListener errorListener)
            throws IOException {
        // 后台会话超时响应码改为401，为做兼容按成功处理，
        if (response.isSuccessful() || response.code() == 401) {
            final String responseBodyString = response.body().string();
            if (ZoomSPUtils.getEncryption()) {
                try {
                    String result = SM4Utils.decryptData_CBC(SM4_KEY, SM4_IV, responseBodyString);
                    final String s = DataConversionUtil.hexStr2Str(result);
                    UIHandler.get().post(new Runnable() {
                        @Override
                        public void run() {
                            if (listener != null) {
                                listener.onResponse(s);
                            }
                        }
                    });
                } catch (Exception e) {
                    e.printStackTrace();

                    UIHandler.get().post(new Runnable() {
                        @Override
                        public void run() {
                            if (listener != null) {
                                listener.onResponse(responseBodyString);
                            }
                        }
                    });
                }
            } else {
                UIHandler.get().post(new Runnable() {
                    @Override
                    public void run() {
                        if (listener != null) {
                            listener.onResponse(responseBodyString);
                        }
                    }
                });
            }
        } else {
            String responseBodyString = response.body().string();
            onHttpRequestFail(new OkHttpManager.OkHttpServerError(responseBodyString), errorListener);
        }
    }

    /**
     * HTTP同步请求失败处理
     */
    private static void onHttpRequestSyncFail(
            final IOException e,
            final OkHttpManager.ErrorListener errorListener
    ) {
        if (errorListener != null) {
            errorListener.onErrorResponse(new OkHttpManager.OkHttpError(e.getMessage()));
        }
    }

    /**
     * HTTP同步请求成功结果处理
     */
    private static void onHttpRequestSyncResponse(
            Response response,
            final OkHttpManager.Listener<String> listener,
            OkHttpManager.ErrorListener errorListener
    ) throws IOException {
        // 后台会话超时响应码改为401，为做兼容按成功处理，
        if (response.isSuccessful() || response.code() == 401) {
            final String responseBodyString = response.body().string();
            if (ZoomSPUtils.getEncryption()) {
                try {
                    String result = SM4Utils.decryptData_CBC(SM4_KEY, SM4_IV, responseBodyString);
                    final String s = DataConversionUtil.hexStr2Str(result);
                    if (listener != null) {
                        listener.onResponse(s);
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
            } else {
                if (listener != null) {
                    listener.onResponse(responseBodyString);
                }
            }
        } else {
            String responseBodyString = response.body().string();
            onHttpRequestFail(new OkHttpManager.OkHttpServerError(responseBodyString), errorListener);
        }
    }

    /**
     * 网络同步请求的封装，只需要实现Listener，ErrorListener 对数据进行加密上传 post请求
     *
     * @param context       上下文
     * @param url           请求地址
     * @param param         请求参数
     * @param listener      响应监听事件
     * @param errorListener 错误监听事件
     */
    public static void postSync(
            final Context context,
            String url,
            String header,
            final BaseRequestParams param,
            OkHttpManager.Listener<String> listener,
            OkHttpManager.ErrorListener errorListener) {
        httpRequestSync(context, context, METHOD.POST, url, header, param, listener, errorListener);
    }

    /**
     * 网络请求的封装，只需要实现Listener，ErrorListener 对数据进行加密上传 post请求
     *
     * @param context       上下文
     * @param url           请求地址
     * @param param         请求参数
     * @param listener      响应监听事件
     * @param errorListener 错误监听事件
     */
    public static void post(
            final Context context,
            String url,
            String header,
            final BaseRequestParams param,
            OkHttpManager.Listener<String> listener,
            OkHttpManager.ErrorListener errorListener) {
        httpRequest(context, context, METHOD.POST, url, header, param, listener, errorListener);
    }

    public static void post(
            final Fragment fragment,
            String url,
            String header,
            final BaseRequestParams param,
            OkHttpManager.Listener<String> listener,
            OkHttpManager.ErrorListener errorListener) {
        httpRequest(fragment.getActivity(), fragment, METHOD.POST, url, header, param, listener, errorListener);
    }

    /**
     * 特殊的处理方式（只适合掌机）
     *
     * @param context
     * @param url
     * @param params
     * @param listener
     * @param errorListener
     */
    public static void postFileCreateNewURL(final Context context,
                                            String url,
                                            final BaseRequestParams params,
                                            final OkHttpManager.Listener<String> listener,
                                            final OkHttpManager.ErrorListener errorListener) {

        Request.Builder requestBuilder = createPostFileRequestBuilder(context, url, params);

        OkHttpManager.getClient(context).newCall(requestBuilder.build()).enqueue(new Callback() {
            @Override
            public void onFailure(Call call, final IOException e) {
                onPostFileFail(e, errorListener);
                e.printStackTrace();
            }

            @Override
            public void onResponse(Call call, Response response) throws IOException {
                onPostFileResponse(response, listener, errorListener);
            }
        });
    }

    private static Request.Builder createPostFileRequestBuilder(Context context,
                                                                String url,
                                                                final BaseRequestParams params) {
        //-------------组织新的post地址--------------

        StringBuilder sb = new StringBuilder();
        sb.append(url + "?");
        for (ConcurrentHashMap.Entry<String, String> entry : params.urlParams.entrySet()) {
            sb.append(entry.getKey());
            sb.append('=');
            sb.append(entry.getValue());
            sb.append('&');
        }
        String getUrl = sb.substring(0, sb.length() - 1);
        LogUtil.d("HttpClientUtils postFileCreateNewURL()", "新的上传文件路径：" + getUrl);
        //-------------------上传------------
        Mybody body = new Mybody(params);
        Request.Builder requestBuilder = new Request.Builder()
                .url(getUrl)
                .post(body)
                .addHeader("content-type", "")
                .tag(context);

        return requestBuilder;
    }

    private static void onPostFileFail(final IOException e, final OkHttpManager.ErrorListener errorListener) {
        UIHandler.get().post(new Runnable() {
            @Override
            public void run() {
                if (errorListener != null) {
                    if (e instanceof SocketTimeoutException) {
                        errorListener.onErrorResponse(new OkHttpManager.OkHttpTimeoutError(e.getMessage(), e));
                    } else if (e != null) {
                        errorListener.onErrorResponse(new OkHttpManager.OkHttpError(e.getMessage(), e));
                    } else {
                        errorListener.onErrorResponse(new OkHttpManager.OkHttpError("postFileCreateNewURL : Unknown Error."));
                    }
                }
            }
        });
    }

    private static void onPostFileResponse(Response response,
                                           final OkHttpManager.Listener<String> listener,
                                           final OkHttpManager.ErrorListener errorListener) throws IOException {
        // 会话超时改为401为兼容之前版本按请求成功处理
        if (response.isSuccessful() || response.code() == 401) {
            final String responseBodyString = response.body().string();
            UIHandler.get().post(new Runnable() {
                @Override
                public void run() {
                    if (listener != null) {
                        listener.onResponse(responseBodyString);
                    }
                }
            });
        } else {
            onPostFileFail(new OkHttpManager.OkHttpServerError(SERVER_ERROR), errorListener);
        }
    }

    public static void get(
            final Context context,
            String url,
            final BaseRequestParams param,
            OkHttpManager.Listener<String> listener, OkHttpManager.ErrorListener errorListener) {
        httpRequest(context, context, METHOD.GET, url, "", param, listener, errorListener);
    }

    public static void get(
            final Context context,
            final Object callObject,
            String url,
            final BaseRequestParams param,
            OkHttpManager.Listener<String> listener, OkHttpManager.ErrorListener errorListener) {
        httpRequest(context, callObject, METHOD.GET, url, "", param, listener, errorListener);
    }

    public static void put(
            final Context context,
            String url,
            final BaseRequestParams param,
            OkHttpManager.Listener<String> listener, OkHttpManager.ErrorListener errorListener) {
        httpRequest(context, context, METHOD.PUT, url, "", param, listener, errorListener);
    }

    public static void delete(
            final Context context,
            String url,
            final BaseRequestParams param,
            OkHttpManager.Listener<String> listener, OkHttpManager.ErrorListener errorListener) {
        httpRequest(context, context, METHOD.DELETE, url, "", param, listener, errorListener);
    }

    /**
     * 下载文件
     *
     * @param context      上下文
     * @param type         类型  0 不使用进度条 1使用进度条
     * @param fileUrl      下载文件的url路径
     * @param fileSavePath 下载文件的保存路径
     * @param listener     下载侦听
     */
    public static void download(
            Context context,
            final int type,
            String fileUrl,
            final String fileSavePath,
            final OkHttpManager.DownLoadListener listener
    ) {
        final Request request = new Request.Builder()
                .url(fileUrl)
                .tag(context)
                .addHeader("Accept-Encoding", "identity")
                .build();

        OkHttpManager.getClient(context).newCall(request).enqueue(new Callback() {
            @Override
            public void onFailure(Call call, final IOException e) {
                onDownloadFail(e, listener);
            }

            @Override
            public void onResponse(Call call, Response response) throws IOException {
                onDownloadResponse(type, fileSavePath, response, listener);
            }
        });
    }

    private static void onDownloadFail(final IOException e, final OkHttpManager.DownLoadListener listener) {
        UIHandler.get().post(new Runnable() {
            @Override
            public void run() {
                if (listener != null) {
                    if (e instanceof SocketTimeoutException) {
                        listener.onFailure(new OkHttpManager.OkHttpTimeoutError(e.getMessage(), e));
                    } else if (e != null) {
                        listener.onFailure(new OkHttpManager.OkHttpError(e.getMessage(), e));
                    } else {
                        listener.onFailure(new OkHttpManager.OkHttpError("download:Unknown Error."));
                    }
                }
            }
        });
    }

    private static void onDownloadResponse(final int type,
                                           String fileSavePath,
                                           Response response,
                                           final OkHttpManager.DownLoadListener listener) {

        if (response.code() == 401) {
            onUpDownloadFail(new OkHttpManager.OkHttpServerError(SESSION_OUT_OF_TIME), listener);
        } else if (response.isSuccessful()) {
            saveDownloadFile(response, fileSavePath, listener);
        } else {
            onDownloadFail(new OkHttpManager.OkHttpServerError(SERVER_ERROR), listener);
        }
    }

    /**
     * 下载文件
     *
     * @param context      上下文
     * @param type         类型  0 不适用进度条 1使用进度条
     * @param fileUrl      下载文件的url路径
     * @param fileSavePath 下载文件的保存路径
     * @param listener     下载侦听
     */
    public static void upDownload(final Context context, final int type, String fileUrl, final String fileSavePath, String progress,
                                  boolean isCancle, final OkHttpManager.DownLoadListener listener) {
        if (isCancle) {
            //暂停
            pause(fileUrl);
            return;
        }
        Call call = createUpDownloadCall(context, fileUrl, progress);

        call.enqueue(new Callback() {
            @Override
            public void onFailure(Call call, final IOException e) {
                onUpDownloadFail(e, listener);
            }

            @Override
            public void onResponse(Call call, Response response) throws IOException {
                onUpDownloadResponse(type, fileSavePath, response, listener);
            }
        });


    }

    private static Call createUpDownloadCall(Context context, String fileUrl, String progress) {
        if (!TextUtils.isEmpty(progress)) {
            //断点续传要用到的，指示下载的区间
            request = new Request.Builder()
                    .url(fileUrl)
                    .tag(context)
                    .addHeader("RANGE", "bytes=" + Long.parseLong(progress) + "-") //断点续传要用到的，指示下载的区间
                    .build();
        } else {
            request = new Request.Builder()
                    .url(fileUrl)
                    .tag(context)
                    .addHeader("Accept-Encoding", "identity")
                    .build();
        }
        if (mClient == null) {
            mClient = OkHttpManager.getClient(context);
        }
        Call call = mClient.newCall(request);
        if (downCalls == null) {
            downCalls = new HashMap<>();
        }
        downCalls.put(fileUrl, call);

        return call;
    }

    private static void onUpDownloadFail(final IOException e, final OkHttpManager.DownLoadListener listener) {
        UIHandler.get().post(new Runnable() {
            @Override
            public void run() {
                if (listener != null) {
                    if (e instanceof SocketTimeoutException) {
                        listener.onFailure(new OkHttpManager.OkHttpTimeoutError(e.getMessage(), e));
                    } else if (e != null) {
                        listener.onFailure(new OkHttpManager.OkHttpError(e.getMessage(), e));
                    } else {
                        listener.onFailure(new OkHttpManager.OkHttpError("upDownload : Unknown Error."));
                    }
                }
            }
        });
    }

    private static void onUpDownloadResponse(final int type,
                                             String fileSavePath,
                                             Response response,
                                             final OkHttpManager.DownLoadListener listener) {
        // 后台会话超时响应码改为401，为做兼容按成功处理，
        if (response.code() == 401) {
            onUpDownloadFail(new OkHttpManager.OkHttpServerError(SESSION_OUT_OF_TIME), listener);
        } else if (response.isSuccessful()) {
            saveDownloadFile(response, fileSavePath, listener);
        } else {
            onUpDownloadFail(new OkHttpManager.OkHttpServerError(SERVER_ERROR), listener);
        }

    }

    public static void saveDownloadFile(Response response, String target, OkHttpManager.DownLoadListener listener) {
        try {

            InputStream inputStream = response.body().byteStream();

            long total = response.body().contentLength();
            if (total <= 0) {
                String fileSize = response.headers().get("fileSize");
                if (fileSize != null) {
                    total = Long.parseLong(fileSize);
                }
            }

            FileOutputStream fileOutputStream = new FileOutputStream(target);
            byte[] bytes = new byte[1024];
            int len = 0;
            long current = 0;
            while ((len = inputStream.read(bytes)) != -1) {
                fileOutputStream.write(bytes, 0, len);
                current += len;
                listener.onProgress(current, total);
//                onSaveDownloadFile2Progress(current, total, listener);
            }
            fileOutputStream.close();
            inputStream.close();
            listener.onSuccess(new File(target));
//            onSaveDownloadFile2Success(new File(target), listener);
            Log.e(TAG, "saveDownloadFile: " + target);
        } catch (Exception e) {
            listener.onFailure(new OkHttpManager.OkHttpError("catch异常" + e.getLocalizedMessage()));
//            onSaveDownloadFile2Fail(e, listener);
            listener.onFailure(new OkHttpManager.OkHttpError(e.getMessage(), e));
        }


    }

    /**
     * 暂停
     */
    public static void pause(String url) {
        Call call = downCalls.get(url);
        if (call != null) {
            call.cancel();//取消
        }
        downCalls.remove(url);
    }


    public static void onSaveDownloadFile2Success(final File file, final OkHttpManager.DownLoadListener listener) {
        //结束回调
        UIHandler.get().post(new Runnable() {
            @Override
            public void run() {
                if (listener != null) {
                    listener.onSuccess(file);
                }
            }
        });
    }

    public static void onSaveDownloadFile2Progress(final long finalEnd, final long total, final OkHttpManager.DownLoadListener listener) {
        UIHandler.get().post(new Runnable() {
            @Override
            public void run() {
                if (listener != null) {
                    listener.onProgress(finalEnd, total);
                }
            }
        });
    }

    public static void onSaveDownloadFile2Fail(final Exception e, final OkHttpManager.DownLoadListener listener) {
        //失败回调
        UIHandler.get().post(new Runnable() {
            @Override
            public void run() {
                if (listener != null) {
                    listener.onFailure(new OkHttpManager.OkHttpError(e.getMessage(), e));
                }
            }
        });
    }


    /**
     * 按tag取消请求.
     * 源自: http://www.jianshu.com/p/ab41007f95c5
     *
     * @param context
     */
    public static void cancle(Context context) {
        if (context == null) {
            return;
        }
        synchronized (OkHttpManager.getClient(context).dispatcher().getClass()) {
            for (Call call : OkHttpManager.getClient(context).dispatcher().queuedCalls()) {
                if (context.equals(call.request().tag())) {

                    call.cancel();
                }
            }

            for (Call call : OkHttpManager.getClient(context).dispatcher().runningCalls()) {
                if (context.equals(call.request().tag())) {
                    call.cancel();
                }
            }
        }
    }

    public static void cancle(Fragment fragment) {
        if (fragment == null) {
            return;
        }
        synchronized (OkHttpManager.getClient(fragment.getActivity()).dispatcher().getClass()) {
            for (Call call : OkHttpManager.getClient(fragment.getActivity()).dispatcher().queuedCalls()) {
                if (fragment.equals(call.request().tag())) {
                    call.cancel();
                }
            }

            for (Call call : OkHttpManager.getClient(fragment.getActivity()).dispatcher().runningCalls()) {
                if (fragment.equals(call.request().tag())) {
                    call.cancel();
                }
            }
        }
    }
}
